//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <crust.h>
#include <svrobj.h>
#include <idmanage.h>
#include <syscall.h>
#include <clsinfo.h>
#include <kmarshal.h>
#include <kprxstub.h>
#include <ckernel.h>
#ifdef _neptune
#include <nu_api.h>
#endif
typedef struct _ServThdArg {
    union {
        IStub               *pIStub;
        InterfaceStruct     *pInterface;
    };
    UInt32   uInvokeEntry;
    UInt32   uBufferSize;
} ServThdArg;

#ifdef DEBUG_KMUTEX
static KMutex  s_ImportSrvLock(__FILE__, __LINE__);
#else
static KMutex  s_ImportSrvLock;
#endif //DEBUG_KMUTEX

#ifdef _mips
uint32_t    g_uNumberOfSysCall = c_uNumOfSystemCall - 1;
#endif

virtaddr_t g_fnSystemCalls[c_uNumOfSystemCall];

Int32 ServerThreadEntry(void * pServThdArg)
{
    Thread * pThread;
    UInt32 uStackTop;

    pThread = GetCurrentThread();

    assert(pThread->m_uUserStackBase);
    uStackTop = pThread->m_uUserStackBase + USER_STACK_SIZE
            - USER_STACK_PRESERVED_SIZE;

    memset((void *)(uStackTop + USER_STACK_PRESERVED_SIZE - TLS_SIZE),
            0, TLS_SIZE);

    uStackTop = uStackTop - 16
            - RoundUp2(((ServThdArg *)pServThdArg)->uBufferSize, sizeof(int));

    *((int*)(uStackTop + 4)) = (Int32)(((ServThdArg *)pServThdArg)->pIStub);
    *((int*)(uStackTop + 8)) = (int)(uStackTop + 16);
    *((int*)(uStackTop + 12)) = ((ServThdArg *)pServThdArg)->uBufferSize;
    memcpy((UInt32 *)(uStackTop + 16), pThread->m_pBuffer, \
        ((ServThdArg *)pServThdArg)->uBufferSize);

    pThread->SetUserEntry( \
        (void *)((Byte *)uStackTop), \
        (void *)((ServThdArg *)pServThdArg)->uInvokeEntry);
                                            // vtbl entry of Invoke() method
    UInt32 handle[] = {
        (UInt32)pThread,
        ((ServThdArg *)pServThdArg)->uInvokeEntry
    };
    TryToSendReceiveDebugMsg(DEBUGGEE_THREAD_CREATE, (UInt32)handle);

    free(pServThdArg);

    return 0;
}

EXTERN KMutex g_marshalLock;

ECode  _SysRegister(IStub *pIStub, UInt32 uIndex, oid_t *pOid,
    CIClassEntry ** ppClsInfo, CProcess * pCProcess)
{
    Object * pObject;

    pObject = new Object;
    if (!pObject) {
        return E_OUT_OF_MEMORY;
    }

    g_marshalLock.Lock();
    pObject->Init(pCProcess, pIStub, uIndex, ppClsInfo, NULL);
    AddObject(pObject);
    g_marshalLock.Unlock();

    if (pOid) {
        *pOid = pObject->m_oid;
    }

    return NOERROR;
}

STATIC DLinkNode s_serviceWaiterList;
#ifdef DEBUG_KMUTEX
STATIC KMutex s_serviceWaiterListLock(__FILE__, __LINE__);
#else
STATIC KMutex s_serviceWaiterListLock;
#endif //DEBUG_KMUTEX
struct ServiceWaiter : public DLinkNode
{
    wchar_t *pwszName;
    DzEvent   event;
};

class ServiceWaiterUndoOperation : public UndoOperation
{
public:
    ServiceWaiterUndoOperation(ServiceWaiter *pWaiter)
    {
        assert(pWaiter);
        m_pWaiter = pWaiter;
    }

    virtual void Undo(Thread *pThread);

private:
    ServiceWaiter *m_pWaiter;
};

void ServiceWaiterUndoOperation::Undo(Thread *pThread)
{
    s_serviceWaiterListLock.Lock();
    m_pWaiter->Detach();
    delete m_pWaiter->pwszName;
    s_serviceWaiterListLock.Unlock();
}

STATIC void NotifyServiceWaiters(const wchar_t * pwszName)
{
    register ServiceWaiter *pServiceWaiter;

    s_serviceWaiterListLock.Lock();
    ForEachDLinkNode(ServiceWaiter *, pServiceWaiter, &s_serviceWaiterList) {
        if (0 == wcscmp(pwszName, pServiceWaiter->pwszName)) {
            pServiceWaiter->event.Notify();
        }
    }
    s_serviceWaiterListLock.Unlock();
}

ECode _SysRegisterCommon(const wchar_t * pwszName, IStub * pIStub,
    UInt32 uIndex, oid_t * pOid,
    CIClassEntry ** ppClsInfo, CProcess * pCProcess)
{
    Object * pObject;
    NameHook * pNameHook;

    assert(pwszName);
    g_marshalLock.Lock();

    pNameHook = NameHook::Find(pwszName);
    if (pNameHook) {
        g_marshalLock.Unlock();
        kprintf("the named service have existed\n");
        return E_ALREADY_EXIST;
    }

    pObject = new Object;
    if (!pObject) {
        g_marshalLock.Unlock();
        return E_OUT_OF_MEMORY;
    }

    pNameHook = NameHook::Create(pObject, GetCurrentProcess(), pwszName);
    if (!pNameHook) {
        delete pObject;
        g_marshalLock.Unlock();
        return E_OUT_OF_MEMORY;
    }

    // Note it differs from _SysRegister
    pObject->Init(pCProcess, pIStub, uIndex, ppClsInfo, pNameHook);
    AddObject(pObject);

    if (pOid) {
        *pOid = pObject->m_oid;
    }

    NotifyServiceWaiters(pwszName);

    g_marshalLock.Unlock();

    return NOERROR;
}

DECL_SYSTEMCALL SysRegister(IStub * pIStub, EMuid * pCLSID, EIID * pIID,
    oid_t * pOid, CIClassEntry ** ppClsInfo)
{
    UInt32 uIndex = 0;

    if (NULL != ppClsInfo) { // It's not a system Object
        for (int n = 0; n < (*ppClsInfo)->interfaceNum; n++) {
            CIInterfaceEntry *pInterfaceInfo =
                (CIInterfaceEntry *)GetUnalignedPtr(
                    (*ppClsInfo)->interfaces + n);
            if (pInterfaceInfo->iid == *pIID) {
                uIndex = n;
                break;
            }
        }
    }

    return _SysRegister(pIStub, uIndex, pOid, \
                        ppClsInfo, GetCurrentProcess());
}

DECL_SYSTEMCALL SysUnregister(oid_t oid)
{
    return DeleteObject(oid);
}

DECL_SYSTEMCALL SysRegisterCommon(const wchar_t * pwszName,
    IStub * pIStub, RegInArg* pRegInArg,
    oid_t * pOid, CIClassEntry ** ppClsInfo)
{
    UInt32 uIndex = 0;

    if (NULL != ppClsInfo) { // It's not a system Object
        for (int n = 0; n < (*ppClsInfo)->interfaceNum; n++) {
            CIInterfaceEntry *pInterfaceInfo =
                (CIInterfaceEntry *)GetUnalignedPtr(
                    (*ppClsInfo)->interfaces + n);
            if (pInterfaceInfo->iid == *(pRegInArg->pIID)) {
                uIndex = n;
                break;
            }
        }
    }
    return  _SysRegisterCommon(pwszName, pIStub, uIndex, pOid, \
                                ppClsInfo, GetCurrentProcess());
}

DECL_SYSTEMCALL SysResolveCommon(const wchar_t * pwszName, oid_t * pOid,
    EMuid * pClsid, UInt32 * puIndex,
    ResolveOutArg * pResolveOutArg)
{
    Object * pObject;
    NameHook * pNameHook;

    g_marshalLock.Lock();

    pNameHook = NameHook::Find(pwszName);
    if (!pNameHook) {
        g_marshalLock.Unlock();
        return E_DOES_NOT_EXIST;
    }

    assert(pNameHook->m_pObject);

    pObject = pNameHook->m_pObject;
    if (NULL == pObject->m_pCProcess) {
        *(pResolveOutArg->ppContext) = CTX_USER_2_KERN;
    }
    else if (pObject->m_pCProcess != GetCurrentProcess()) {
        *(pResolveOutArg->ppContext) = CTX_DIFF_PROCESS;
    }
    else { // in the same user process space
        *(pResolveOutArg->ppContext) = CTX_SAME_PROCESS;
    }

    if (pOid) {
        *pOid = pObject->m_oid;
    }
    if (pClsid) {
        *pClsid = pObject->m_clsid;
    }
    if (puIndex) {
        *puIndex = pObject->m_uIndex;
    }
    if (pResolveOutArg->ppClsInfo) {
        *(pResolveOutArg->ppClsInfo) = pObject->m_pClsInfo;
    }

    g_marshalLock.Unlock();

    return NOERROR;
}

DECL_SYSTEMCALL SysUnregisterCommon(const wchar_t * pwszName)
{
#if (_TEST_TYPE == 4)  /* Test for CAR performance */
    return NOERROR;
#endif // _TEST_TYPE == 4

    NameHook * pNameHook;

    g_marshalLock.Lock();

    pNameHook = NameHook::Find(pwszName);
    if (!pNameHook || !(pNameHook->m_pObject)) {
        g_marshalLock.Unlock();
        return E_DOES_NOT_EXIST;
    }

    if (pNameHook->m_pProcess != GetCurrentProcess()) {
        g_marshalLock.Unlock();
        return E_INVALID_OPERATION;
    }

    // here delete the NameHook and release the stub
    ECode ec = NameHook::DestroyAndRelease(pNameHook);

    g_marshalLock.Unlock();

    return ec;
}

EXTERN KMutex g_objectLock;

DECL_SYSTEMCALL SysInvoke(InvokeInArg * pInvokeInArg, void *pvInBuf,
    size_t uInBufSize, void *pvOutBuf, size_t uOutBufSize)
{
    Object * pObject;
    CProcess * pCProcess;
    IStub   * pIStub;
    ECode ec;

    assert(pInvokeInArg->oid == ((MarshalHeader *)pvInBuf)->m_oid);

    g_objectLock.Lock();
    pObject = GetObject(pInvokeInArg->oid);
    if (NULL == pObject) {
        g_objectLock.Unlock();
        return E_DOES_NOT_EXIST;
    }
    pIStub = pObject->m_pIStub;
    assert(pIStub);
    pCProcess = pObject->m_pCProcess;
    if (NULL == pCProcess) { // it's a kernel Object
        g_objectLock.Unlock();
        ec = pIStub->Invoke(pvInBuf, uInBufSize, pvOutBuf, uOutBufSize);
        return ec;
    }
    else {
        UInt32 uInvokeEntry = pObject->m_uInvokeEntry;
        pCProcess->AddRef();
        g_objectLock.Unlock();

        // TODO: now we simply consider the service comes from
        // another process
        //
        Thread * pThread;
        ServThdArg * pServThdArg;
        ECode exitCode;
        size_t uBufSize;

        if (ProcessState_Finished == pCProcess->m_processState) {
            pCProcess->Release();
            return E_PROCESS_ALREADY_EXITED;
        }

        // BUGBUG: if the process be killed in there,
        // what will be happen?
        ec = pCProcess->GetThread(&pThread);
        if (FAILED(ec)) {
            pCProcess->Release();
            return ec;
        }

        uBufSize = MAX(uInBufSize, uOutBufSize);

        // BUGBUG: uBufSize LIMITATION:
        //
        // NOTE: Now the user stack size is 4MB and the top 1KB is
        // reserved for TLS and Error Info, so we limit the ubufSize
        // should be less than (??)
        //
        if (uBufSize > MAX_MSH_SIZE + 0x1000) {
            pThread->Release();
            pCProcess->Release();
            return E_OUT_OF_MEMORY;
        }
        if (pThread->m_uBufferSize < uBufSize) {
            if (!pThread->ReallocBuffer(uBufSize)) {
                pThread->Release();
                pCProcess->Release();
                return E_OUT_OF_MEMORY;
            }
        }

        memcpy(pThread->m_pBuffer, pvInBuf, uInBufSize);
        pServThdArg = (ServThdArg *)malloc(sizeof(ServThdArg));
        if (NULL == pServThdArg) {
            pThread->Release();
            pCProcess->Release();
            return E_OUT_OF_MEMORY;
        }
        pServThdArg->pIStub = pIStub;
        pServThdArg->uInvokeEntry = uInvokeEntry;
        pServThdArg->uBufferSize = uInBufSize;
        pThread->SetKernelEntry(ServerThreadEntry, (void *)pServThdArg);

        pThread->m_pClientThread = GetCurrentThread();
        ec = pThread->Start();
        if (NOERROR != ec) {
            assert(E_PROCESS_ALREADY_EXITED == ec);
            pThread->Release();
            pCProcess->Release();
            free(pServThdArg);
            return E_PROCESS_ALREADY_EXITED;
        }

        if (!pInvokeInArg->async) {
            pThread->m_joinEvent.UninterruptibleWait(NULL);

            uOutBufSize = ((MarshalHeader *)pThread->m_pBuffer)->m_uOutSize;

            if (0 != uOutBufSize && (SUCCEEDED(pThread->m_exitCode) ||
                    IsUserECode(pThread->m_exitCode))) {

                memcpy(pvOutBuf, pThread->m_pBuffer, uOutBufSize);
            }

            exitCode = pThread->m_exitCode;
            pThread->Release();
            pCProcess->Release();
            return exitCode;
        }
        pThread->Release();
        pCProcess->Release();

        return NOERROR;
    }
}

DECL_SYSTEMCALL SysReply(ECode ec,
    void *pvOutBuf, size_t uOutBufSize)
{
    Thread * pThread;

    pThread = GetCurrentThread();
    if (0 != uOutBufSize) {

        assert(uOutBufSize == ((MarshalHeader *)pvOutBuf)->m_uOutSize);

        if (pThread->m_uBufferSize < uOutBufSize) {
            if (!pThread->ReallocBuffer(uOutBufSize)) {
                return E_OUT_OF_MEMORY;
            }
        }

        memcpy(pThread->m_pBuffer, pvOutBuf, uOutBufSize);
    }
    SysExitThread(ec);

    return NOERROR;
}

DECL_SYSTEMCALL SysPrint(const wchar_t *wszMessage)
{
#ifndef ELASTOS_RC    
    if (NULL == wszMessage) return E_INVALID_ARGUMENT;

    // TODO(mips): wchar_t
    // BUGBUG: If the message to long, the stack maybe overflow.
#if defined(_GNUC) && defined(_mips)
    char *sz = (char*)malloc(wcslen(wszMessage) * 2 + 1);
    if (NULL == sz) return E_OUT_OF_MEMORY;
    unsigned short *puMes = (unsigned short *)wszMessage;
    char *p = sz;
    while (*puMes) {
        *p++ = (char)*puMes++;
    }
    *p = '\0';
#else
    uint_t uLength = wcslen(wszMessage) + 1;

    char *szMessage = (char *)malloc(uLength);
    if (NULL == szMessage) return E_OUT_OF_MEMORY;

    uint_t i;
    for (i = 0; i < uLength - 1; i++) {
        szMessage[i] = (char)wszMessage[i];
    }
    szMessage[i] = '\0';
#endif

    kputs(szMessage);

    free(szMessage);
#endif
    return NOERROR;
}

DECL_SYSTEMCALL SysGetMemtraceArgs(wchar_t *pwchArgId, Int32 *pIndex,
    Address *pWatchAddr)
{
    CProcess *pCurrentProcess = GetCurrentProcess();
    assert(pCurrentProcess != NULL);

    pCurrentProcess->GetArgsId(pwchArgId);
    pCurrentProcess->GetProIndex(pIndex);
    pCurrentProcess->GetWatchAddress(pWatchAddr);

    return NOERROR;
}

ECode GetVirtualCode(struct KBDStatus *pVirtulCode);

DECL_SYSTEMCALL SysGetVirtualCode(struct KBDStatus *pVirtulCode)
{
#if defined(_x86) && !defined(__NO_DRIVERS)
    return GetVirtualCode(pVirtulCode);
#else
    return E_NOT_IMPLEMENTED;
#endif
}

DECL_SYSTEMCALL SysReboot()
{
    TriggerSystemEvent(SystemEvent_Shutdown);
    DzSleep(1 * c_uTickRate, NULL);

    BspReboot();

    return NOERROR;
}

DECL_SYSTEMCALL SysBreak(uint_t uAddr)
{
    return GetCurrentProcess()->m_AS.Break(uAddr);
}

DECL_SYSTEMCALL SysRegisterClassInfo(CIClassInfo *pClassInfo)
{
    if (NULL == pClassInfo) return E_INVALID_ARGUMENT;

    // TODO: here ,we should prevent from registering the same
    // class information again

    return RegisterSharedClassInfo(pClassInfo);
}

DECL_SYSTEMCALL SysGetClassInfo(EMuid *pClsid, CIClassEntry **ppClassInfo)
{
    if (NULL == pClsid || NULL == ppClassInfo) {
        return E_INVALID_ARGUMENT;
    }

    return LookupSharedClassEntry(*pClsid, ppClassInfo);
}

DECL_SYSTEMCALL SysRegisterService(const wchar_t * pwszName, oid_t oid)
{
    Object * pObject;
    NameHook * pNameHook;

    g_marshalLock.Lock();

    pNameHook = NameHook::Find(pwszName);
    if (pNameHook) {
        g_marshalLock.Unlock();
        kprintf("the named service have existed\n");
        return E_ALREADY_EXIST;
    }

    pObject = GetObject(oid);
    if (NULL == pObject) {
        g_marshalLock.Unlock();
        return E_DOES_NOT_EXIST;
    }

    // BUGBUG:
    if (NULL != pObject->m_pNameHook) {
        g_marshalLock.Unlock();
        return E_ALREADY_EXIST;
    }

    pNameHook = NameHook::Create(pObject, GetCurrentProcess(), pwszName);
    if (!pNameHook) {
        g_marshalLock.Unlock();
        return E_OUT_OF_MEMORY;
    }

    if (!pObject->m_pCProcess) {
        // Do nothing
    }
    else if (pObject->m_pCProcess == GetCurrentProcess()) {
        AttachServer(oid, CTX_SAME_PROCESS);
    }
    else {
        AttachServer(oid, CTX_DIFF_PROCESS);
    }

    pObject->m_pNameHook = pNameHook;

    NotifyServiceWaiters(pwszName);

    g_marshalLock.Unlock();

    return NOERROR;
}

DECL_SYSTEMCALL SysWaitService(
    const wchar_t *pwszName, Int32 msTimeout, WaitResult *pResult)
{
    if (NULL == pwszName || NULL == pResult) return E_INVALID_ARGUMENT;

    s_serviceWaiterListLock.Lock();

    if (NameHook::Find(pwszName)) {
        s_serviceWaiterListLock.Unlock();
        *pResult = WaitResult_OK;
        return NOERROR;
    }

    ServiceWaiter swaiter;
    swaiter.pwszName = new wchar_t[wcslen(pwszName) + 1];
    if (NULL == swaiter.pwszName) {
        s_serviceWaiterListLock.Unlock();
        return E_OUT_OF_MEMORY;
    }
    wcscpy(swaiter.pwszName, pwszName);
    s_serviceWaiterList.InsertLast(&swaiter);

    ServiceWaiterUndoOperation undoOpr(&swaiter);
    register Thread *pCurrentThread = GetCurrentThread();
    pCurrentThread->AddUndoOperation(&undoOpr);

    s_serviceWaiterListLock.Unlock();

    WaitResult wr;
    if (INFINITE == msTimeout) {
        swaiter.event.Wait(&wr, NULL);
    }
    else {
        swaiter.event.TryWait(
                DzMillisecondsToTicks(msTimeout), &wr, NULL);
    }

    s_serviceWaiterListLock.Lock();
    swaiter.Detach();
    delete swaiter.pwszName;
    pCurrentThread->RemoveUndoOperation(&undoOpr);
    s_serviceWaiterListLock.Unlock();

    *pResult = wr;
    return NOERROR;
}

ECode AttachServer(oid_t oid, PContext pContext)
{
    DECL_ADDREF_HEADER(header, oid, pContext);
    InvokeInArg invokeInArg  = {oid, FALSE};

    return SysInvoke(&invokeInArg, &header, sizeof(MarshalHeader), NULL, 0);
}

DECL_SYSTEMCALL SysAttachServer(oid_t oid, PContext pContext)
{
    CProcess * pProcess;
    ImportService * pImportService;

    // Add oid of object to the member of process Struct
    // if the client process abort unnormally, we could correct
    // the count of proxy/stub/object through it
    // NOTE: see the way which is done with it in IKernel->ExitProcess
    //
    pImportService = new ImportService;
    if (!pImportService) {
        return E_OUT_OF_MEMORY;
    }
    pImportService->m_oid = oid;
    pImportService->m_pContext = pContext;
    pProcess = GetCurrentProcess();
    s_ImportSrvLock.Lock();
    pProcess->m_importServiceList.InsertNext(pImportService);
    s_ImportSrvLock.Unlock();

    return NOERROR;
}

ECode DetachServer(oid_t oid, PContext pContext)
{
    //if 1, clear asynchronism Release
#if 1
    InvokeInArg invokeInArg  = {oid, FALSE};
#else
    InvokeInArg invokeInArg  = {oid, TRUE};
#endif

    DECL_RELEASE_HEADER(header, oid, pContext);
    ECode ec = SysInvoke(
        &invokeInArg, &header, sizeof(MarshalHeader), NULL, 0);
    if (FAILED(ec)) {
        return ec;
    }

    return NOERROR;
}

DECL_SYSTEMCALL SysDetachServer(oid_t oid, PContext pContext)
{
    ECode ec;
    DLinkNode * pImportService;
    CProcess * pProcess;

    //if 1, clear asynchronism Release
#if 1
    InvokeInArg invokeInArg  = {oid, FALSE};
#else
    InvokeInArg invokeInArg  = {oid, TRUE};
#endif

    // remote Release stub
    DECL_RELEASE_HEADER(header, oid, pContext);
    ec = SysInvoke(&invokeInArg, &header, sizeof(MarshalHeader), NULL, 0);
    if (FAILED(ec)) {
        return ec;
    }

    // Remove oid of object from the member of process Struct
    // and that prove the client process have used the service
    // correctly and we don't need to keep the oid anymore
    pProcess = GetCurrentProcess();
    s_ImportSrvLock.Lock();
    pImportService = pProcess->m_importServiceList.Next();
    while (pImportService != &(pProcess->m_importServiceList)) {
        if (((ImportService *)pImportService)->m_oid == oid) {
            pImportService->Detach();
            s_ImportSrvLock.Unlock();
            delete(pImportService);
            return NOERROR;
        }
        pImportService = pImportService->Next();
    }

    s_ImportSrvLock.Unlock();
    return E_NO_IMPORT_SERVER;
}

extern KMutex g_marshalLock;

ECode DzRegisterService(
    const wchar_t *pwszServiceName, PInterface pObj, IStub **ppIStub)
{
    ECode ec;

    assert(wcslen(pwszServiceName) <= MAXIMUM_SERVICE_NAME_LENGTH);

    g_marshalLock.Lock();
    ec = CObjectStub::S_CreateObject(pwszServiceName, pObj, ppIStub);
    g_marshalLock.Unlock();
    return ec;
}

ECode DzUnregisterService(const wchar_t * pwszName, IStub *pIStub)
{
    ECode ec = SysUnregisterCommon(pwszName);
    if (FAILED(ec)) return ec;

    pIStub->Release();
    return ec;
}

ECode SysExitThread(
    /* [in] */ ECode exitCode)
{
    Thread   *pCurThd = ::GetCurrentThread();
    CProcess *pCurProc = ::GetCurrentProcess();

    if (pCurThd == pCurProc->m_pMainThread) {
        assert(!pCurThd->m_isDllProcDetachThd);
        g_pCKernel->ExitProcess((Int32)exitCode);
        assert(0);
    }

    if (ThreadState_Finished != pCurThd->m_uPoolThreadState) {
        DzGetSystemTime(&pCurThd->m_finishTime);
    }

    if (ThreadState_Finished == InterlockedExchange(
            (Int32 *)&pCurThd->m_uPoolThreadState, ThreadState_Finished)) {
        // Current thread being abort. Do nothing here. Don't return.
        //
        UninterruptibleSleep();
        assert(0);
    }

    TryToSendReceiveDebugMsg(DEBUGGEE_THREAD_EXIT,
        (UInt32)pCurThd->m_exitCode);

    pCurThd->m_activeLock._Lock();

    pCurThd->m_exitCode = exitCode;
    pCurThd->m_fnKernelEntry = NULL;
    pCurThd->m_bHasUserEntry = FALSE;

    pCurThd->UndoAll();

    pCurProc->m_threadLock.Lock();
    pCurThd->m_inProcLink.Detach();
    // for detach twice.(In thread release)
    pCurThd->m_inProcLink.Initialize();
    pCurProc->m_nThreadListState++;
    pCurProc->m_threadLock.Unlock();

    pCurThd->m_joinEvent.Notify();

    pCurThd->m_activeLock._Unlock();

    if (pCurThd->m_isDllProcDetachThd) {
        // Current thread is the thread which call DLL_PROCESS_DETACH.
        // This thread will abort and release
        // by CProcess::UnmapAndDeleteModView().
        // Do nothing here. Don't return.
        //
        UninterruptibleSleep();
        assert(0);
    }

    // If thread's reference equal 1, put back pCurThd to thread pool.
    // If the thread pool has overloaded, pCurThd will be destroy.
    pCurThd->Release();

    assert(!pCurThd->IsFinished());

    // If pCurThd destroyed, program can't reach here
    pCurThd->ReadyToStart();

    return NOERROR;
}

ECode SysCreateEvent(
    /* [out] */ PVoid *pEventHandle)
{
    return GetCurrentProcess()->CreateEvent((EventNode **)pEventHandle);
}

ECode SysDestroyEvent(
    /* [in] */ PVoid eventHandle)
{
    return GetCurrentProcess()->DestroyEvent((EventNode *)eventHandle);
}

ECode SysNotifyEvent(
    /* [in] */ PVoid eventHandle)
{
    return GetCurrentProcess()->NotifyEvent((EventNode *)eventHandle);
}

ECode SysWaitEvent(
    /* [in] */ PVoid eventHandle)
{
    return GetCurrentProcess()->WaitEvent((EventNode *)eventHandle);
}

ECode SysSetBreakPoint(
    UInt32 uNo, BreakPointType type, void *pvAddress, UInt32 uLength)
{
    UInt32 uBase = COMMON_BASE - 0x10000;
    UInt32 uSize = PROCESS_TOP - uBase;

    if (FALL_INTO((UInt32)pvAddress, uBase, uSize)
            && FALL_INTO((UInt32)pvAddress + uLength - 1, uBase, uSize)) {
        return SetBreakPoint(uNo, type, pvAddress, uLength);
    }
    else {
        return E_INVALID_ARGUMENT;
    }
}

DECL_SYSTEMCALL SysSleep(int ms, WaitResult *pResult)
{
    return g_pCKernel->Sleep(ms, pResult);
}

DECL_SYSTEMCALL SysQueryPerformanceCounter (Int64 *pPerformanceCount, Int64 *pFrequency)
{
#ifdef _neptune
    if (NULL != pFrequency) {
        *pFrequency = 32768; //32k
    }

    if (NULL != pPerformanceCount) {
        Uint32 msw, lsw;
        nu_getTimer32kTicks(&msw, &lsw);
        *pPerformanceCount = (Int64)((((UInt64)msw) << 32) + (UInt64)lsw);
    }
#elif defined _gingko

#define TIMETOTALTICKS    ((~0UL) / 32500)
#define HIGHCRITICAL      (17 * 60 * 100)
#define OSCR0             ((ioport_t)0x80a00010)

    if (NULL != pFrequency) {
        *pFrequency = 3250000; //3.25M
    }

    if (NULL != pPerformanceCount) {
        UInt32 mh, ml, mz, l_uElapsedTicks;
        l_uElapsedTicks = g_uElapsedTicks;
        ml = Inl(OSCR0);
        mz = l_uElapsedTicks % TIMETOTALTICKS;
        mh = l_uElapsedTicks / TIMETOTALTICKS;
        if ((mz > HIGHCRITICAL) && (!(ml & 0x80000000))) {
            mh ++;
        }
        *pPerformanceCount = (Int64)(((UInt64)mh << 32) + (UInt64)ml);
    }
#endif
    return NOERROR;
}

DECL_SYSTEMCALL SysGetThreadStackTop(UInt32 *pStackTop)
{
    Thread *pThread;
    pThread = GetCurrentThread();
    pThread->GetUserStackTop(pStackTop);

    return NOERROR;
}

extern Address g_Dbgstub_ThreadEntry;
extern Address g_Dbgstub_DebugBreakThread;

/*
 * send miscellaneous data to kernel.
 * supported data type:
 *
 * 0: CSOwnerInfo for detect deadlock.
 *     SysSendToKernel() is called in 
 *     zener/elastosdll/util/Csdetect.cpp
 *
 * 1: save pointers of ThreadEntry and DebugBreakThread
 *     to global vars in dbgstub. this is used for suspending 
 *     a running process. SysSendToKernel() is called in 
 *     zener/elastosdll/eladll/dll/Dllentry.cpp
 */
ECode SysSendToKernel(
    /* [in] */ UInt32 *buf,
    /* [in] */ UInt32 type)
{
    ECode ec = NOERROR;

    switch(type)
    {
#ifdef MULTI_RESOURCE_DEADLOCK_DETECT
    case 0:
    {
        CProcess *pProcess = GetCurrentProcess();
        pProcess->m_nCSOwnerInfo = (int)buf;
        break;
    }
#endif

    case 1:
    {
        if (!buf || 0 == buf[0] || 0 == buf[1]) {
            ec = E_INVALID_ARGUMENT;
            break;
        }

        g_Dbgstub_ThreadEntry = (Address)buf[0];
        g_Dbgstub_DebugBreakThread = (Address)buf[1];
        break;
    }

    default:
        //shouldn't be here.
        ec = E_INVALID_ARGUMENT;
        break;
    }

    return ec;
}

ECode DzQueryPerformanceCounter(Int64 *pPerformanceCount)
{
    return SysQueryPerformanceCounter(pPerformanceCount, NULL);
}

ECode DzQueryPerformanceFrequency(Int64 *pFrequency)
{
    return SysQueryPerformanceCounter(NULL, pFrequency);
}

EXTERN DECL_CODEINIT void CDECL InitSystemCallTable()
{
    s_serviceWaiterList.Initialize();

#define SET_SYSTEMCALL(funcname) \
    g_fnSystemCalls[CallNo_##funcname] = (virtaddr_t)&funcname;

    SET_SYSTEMCALL(SysRegister);
    SET_SYSTEMCALL(SysUnregister);
    SET_SYSTEMCALL(SysInvoke);
    SET_SYSTEMCALL(SysReply);
    SET_SYSTEMCALL(SysPrint);
    SET_SYSTEMCALL(SysRegisterCommon);
    SET_SYSTEMCALL(SysResolveCommon);
    SET_SYSTEMCALL(SysUnregisterCommon);
    SET_SYSTEMCALL(SysBreak);
    SET_SYSTEMCALL(SysRegisterClassInfo);
    SET_SYSTEMCALL(SysGetClassInfo);
    SET_SYSTEMCALL(SysExitThread);
    SET_SYSTEMCALL(SysRegisterService);
    SET_SYSTEMCALL(SysWaitService);
    SET_SYSTEMCALL(SysAttachServer);
    SET_SYSTEMCALL(SysDetachServer);
    SET_SYSTEMCALL(SysCreateEvent);
    SET_SYSTEMCALL(SysDestroyEvent);
    SET_SYSTEMCALL(SysNotifyEvent);
    SET_SYSTEMCALL(SysWaitEvent);
    SET_SYSTEMCALL(SysSetBreakPoint);
    SET_SYSTEMCALL(SysGetVirtualCode);
    SET_SYSTEMCALL(SysReboot);
    SET_SYSTEMCALL(SysGetMemtraceArgs);
    SET_SYSTEMCALL(SysSleep);
    SET_SYSTEMCALL(SysQueryPerformanceCounter);
    SET_SYSTEMCALL(SysGetThreadStackTop);
    SET_SYSTEMCALL(SysSendToKernel);
}
